home *** CD-ROM | disk | FTP | other *** search
- ; Written by Dan Norstedt, Stockholm, Sweden Last edit 17-Feb-1990
- ;
- ; This program is placed in the public domain.
- ;
- ; Use this program to generate MSBPCT.COM for MS-DOS with the commands:
- ;
- ; C>MASM MSBPCG;
- ; C>LINK MSBPCG;
- ; C>MSBPCG >MSBPCT.COM
- ;
- ; The generated MSBPCT.COM file is trick coded, and only contains
- ; printable 7-bit ASCII characters. Thus, it can be sent as text
- ; without modifications, just capture it to disk, trim off excess
- ; text, and execute it. It takes one input argument, the input file.
- ; If no valid file is given, a Usage: message is given.
- ;
- ; The program will decodes about 10Kbyte/sec on my AT hard disk.
- ;
- ; The loader and builder portions of this program may be useful for other
- ; programs, too.
-
- CODE SEGMENT PUBLIC
-
- ASSUME CS:CODE,DS:CODE
-
- ORG 100H
-
- START: JMP GENCOM
-
- ORG 100H+72+1 ; Address where loader starts loading
-
- CODARE:
-
- ;----------------------- beginning of MSBPCT code area -----------------------
-
- INBUF EQU ((Offset MSBEND-Offset START+1FFH) AND 0FF00H)
- INBSIZ EQU 400H
- OUTBUF EQU INBUF+INBSIZ
-
- ; CLD ; Already done in the loader
- MOV DX,Offset MEMTXT
- CMP SP,0FF00H ; Enough memory?
- JB OUTMSG
- MOV SI,80H ; Point at line length byte
- XOR AH,AH
- LODSB ; Get it
- XCHG AX,BX
- MOV Word Ptr [SI+BX],0 ; Clear end of command string
- LEA DX,[SI+1]
- MOV AX,3D00H ; Try to open the file
- INT 21H
- MOV DX,Offset USETXT ; Tell usage if we can't open input file
- JNC OPENOK
- OUTMSG: MOV AX,901H ; Output error text
- EXIT: PUSH AX
- INT 21H
- POP AX ; Set up exit code
- MOV AH,4CH
- INT 21H
- OPENOK: XCHG BX,AX ; Save input handle
- MOV DX,Offset FILTXT ; Output header
- MOV AH,9
- MOV SI,OUTBUF ; Temorary buffer for output filename
- RDMORE: INT 21H
- MOV AH,3FH ; Read a character
- MOV CX,1
- MOV DX,SI
- INT 21H
- ERROR: MOV DX,Offset ERRTXT
- JC OUTMSG ; Error if failure here
- DEC AX
- JNZ OUTMSG
- LODSB
- XCHG AX,DX
- MOV AH,2 ; Prepare for output
- CMP DL,20H
- JA RDMORE ; Printable character -> save and output
- MOV AH,3CH ; Prepare for file create
- XOR CX,CX
- MOV [SI-1],CL ; Make input filename buffer NUL terminated
- MOV DX,OUTBUF ; Pointer to file name
- MOV DI,DX
- INT 21H ; Create output file
- JC ERROR
- XCHG AX,BX ; Save file output file handle in BX
- XCHG AX,BP ; Input file handle to BP
- READBU: PUSH DX ; Save shift count (initial value in DL = 0)
- MOV DX,OUTBUF
- MOV CX,DI
- SUB CX,DX ; Compute size of output buffer
- JZ NOWRIT ; Zero, skip write
- MOV AH,40H ; Write it out
- INT 21H
- JC ERROR
- SUB AX,CX ; Write failed?
- JC ERROR
- NOWRIT: MOV DI,DX ; No, reset output buffer pointer
- MOV DX,INBUF ; Load input buffer pointer
- MOV SI,DX ; Set up for later use
- MOV CX,INBSIZ ; Read one buffer of appropriate size
- MOV AH,3FH
- XCHG BX,BP ; Swap input and output file handles
- INT 21H
- XCHG BX,BP
- JC ERROR
- XCHG AX,CX
- MOV AX,3E00H ; Load good close function code, just in case
- JCXZ EXIT ; End of input file, do the good exit
- POP DX ; Regain shift count (in DL)
- INLOOP: LODSB ; Get a character
- SUB AL,30H
- JL CHRDON ; Junk, throw away
- MOV AH,DH ; Good one, get old saved char to AH
- MOV DH,AL ; Save current instead
- CMP AH,4EH ; Old character flags expansion of NULs?
- JZ NULLS
- SHL AL,1 ; No merge low bits of old char with new char
- SHL AL,1
- XCHG CX,DX ; Get current shift amount (0, 2, 4 or 6)
- SHR AX,CL ; Do shift
- XCHG CX,DX
- SUB DL,2 ; Adjust for new shift factor,old = 0 -> skip?
- JS INLOOR ; Yes, skip
- STOSB ; No, save result of shift operation
- INLOOR: AND DL,6 ; Adjust shift count if DL was = 0
- JMP Short CHRDON ; End loop
- NULLS: CBW ; Expand NUL count
- CWD ; Reset shift count in DL and NULL flag in DH
- PUSH CX ; Save input character left counter
- XCHG AX,CX
- MOV AL,0
- REP STOSB ; Store selected amount of NULs
- POP CX ; Restore counter
- CHRDON: LOOP INLOOP ; Loop for rest of input block
- JMP Short READBU ; Try to read another buffer
-
- USETXT DB 'Usage: MSBPCT file.BOO$'
-
- FILTXT DB 'Unpacking to file: $'
-
- ERRTXT DB 'Error during file I/O$'
-
- MEMTXT DB 'Not enough memory$'
-
- MSBEND:
-
- ;-------------------------- end of MSBPCT code area --------------------------
-
- CODEND:
-
- ;-- Loader starts here; don't touch unless you REALLY know what's going on --
-
- FIXUP MACRO LABL,OFFS,DAT,DA2,DAS
- ORG $+(OFFS)
- LABL Label Byte
- IFNB <DAS>
- IFNB <DA2>
- DB (((DAS) OR 65H)-((DAS) AND 65H)) AND 0FFH,0FFH-(DA2)
- ORG $-1
- ELSE
- DB ((DAS)+65H) AND 0FFH
- ENDIF
- ELSE
- DB 0FFH-((DAT) AND 0FFH)
- IFNB <DA2>
- DB 0FFH-(DA2)
- ORG $-1
- ENDIF
- ENDIF
- ORG $-(OFFS)-1
- ENDM
-
- FIXBYT MACRO ADDR ; Generate "XOR [BX+ADDR-0FFH],AL" with 8-bit offset
- DB 30H,47H,(Offset ADDR-Offset LOADER+100H)-0FFH
- ENDM
-
- FIXBYH MACRO ADDR ; Generate "XOR [BX+ADDR-0FFH],AH" with 8-bit offset
- DB 30H,67H,(Offset ADDR-Offset LOADER+100H)-0FFH
- ENDM
-
- FIXWRD MACRO ADDR ; Generate "XOR [BX+ADDR-0FFH],AX" with 8-bit offset
- DB 31H,47H,(Offset ADDR-Offset LOADER+100H)-0FFH
- ENDM
-
- FIXSUB MACRO ADDR ; Generate "SUB [BX+ADDR-0FFH],AL" with 8-bit offset
- DB 28H,47H,(Offset ADDR-Offset LOADER+100H)-0FFH
- ENDM
-
- LOADER: POP AX
- PUSH AX
- DEC AX ; Load AX with 0FFFFH
- PUSH AX ; Now FF FF 00 00 on stack
- INC SP
- POP BX ; Load BX with 00FF
- FIXBYT XORBXX ; Fix up end of loader code
- FIXBYT XORB1
- FIXBYT XORB2
- FIXWRD XORW1
- FIXWRD XORW2
- DAA ; Load AL with 65H
- FIXSUB SUBB1
- FIXSUB SUBB2
- JNZ J0JMP ; Break pipeline
- J0DST: FIXBYH XORB3
- FIXSUB SUBB3
- FIXSUB SUBB4
- FIXWRD XORX1
-
- ; FC
- CLD ; Set LODSB direction
- FIXUP SUBB1,-1,,,0FCH
- ; 8D7749 LEA SI,[BX+DATA-0FFH] ; Point at 100H+72
- DB 8DH,77H,(Offset DATA-Offset LOADER+100H)-0FFH
- FIXUP XORB1,-3,8DH
- ; 56
- PUSH SI ; Copy SI -> DI
- ; 5F
- POP DI
- ; 46
- INC SI
- J2DST:
- ; 2AC2
- SUB AL,DL ; Compute real code/data byte
- ; AA
- STOSB ; Save it
- FIXUP XORW1,-2,0C2H,0AAH
- J1DST:
- J3DST:
- ; AC
- LODSB ; Get an encoded data byte
- FIXUP XORB2,-1,0ACH
- ; 40
- INC AX
- ; 3C31
- CMP AL,31H ; Printable and >= '0'?
- ; 7CFA
- JL J1DST
- J1SRC: FIXUP SUBB2,-1,,,J1DST-J1SRC
- ; 2C35
- SUB AL,'4'+1 ; Yes, '0'-'3' (or '4' = exit code) ?
- ; 77F3
- JA J2DST ; No, store with current prefix code
- J2SRC: FIXUP SUBB3,-1,,,J2DST-J2SRC
- ; B102
- MOV CL,2
- FIXUP XORB3,-2,0B1H
- ; D2C8
- ROR AL,CL
- FIXUP XORX1,-3,,0D2H,2
- ; 92
- XCHG DX,AX ; Yes, just save shifted value
- FIXUP XORW2,-2,0C8H,92H
- ; 75EF
- JNZ J3DST ; No, contine loop
- J3SRC: FIXUP SUBB4,-1,,,J3DST-J3SRC
- ; 75D7
- J0JMP: JNZ J0DST ; (Dummy branch used to clear prefetch queue)
- J0SRC: FIXUP XORBXX,-1,J0DST-J0SRC
- DB 34H ; Skip over next byte (34H = XOR AL,nn opcode)
-
- DATA: DB "$" ; CRLF data to make sure JL J1DST taken first time
-
- GENCOM: PUSH CS ; Allow use without EXE2BIN
- POP DS
- MOV DX,Offset LOADER ; Output LOADER code (!)
- MOV AH,9
- INT 21H
- CLD
- MOV SI,Offset CODARE ; Pointer to real MSBPCT code
- XOR BP,BP ; Reset columns left counter
- MOV BH,17 ; Assure that BH not in range '0'-'3'
- BYTLOP: MOV AX,0C01H
- SUB AL,[SI] ; Convert MSBPCT code to loader format
- INC SI
- MOV CL,2
- SHL AX,CL ; First byte is top 2 bits of byte+43H
- NOT AL
- SHR AL,CL ; Second byte is low 6 bits of -byte-3
- ADD AL,35H ; Based value is '5' for second byte
- CMP AH,BH ; Same prefix as previous byte?
- MOV BH,AH
- XCHG DX,AX
- OUTBYT: XCHG DH,DL ; Swap output order
- JZ OUTNHI ; Skip unnecessary prefix byte
- DEC BP
- JG OUTNCR ; Not 72 chars on the line yet
- PUSH DX
- MOV DX,Offset CRLF ; 72 chars on line, add CR LF
- MOV AH,9
- INT 21H
- MOV BP,72 ; Restart line pointer
- POP DX
- OUTNCR: MOV AH,2 ; Output a byte
- INT 21H
- OUTNHI: XOR DL,DL ; Clear out used code byte
- AND DH,DH ; Anything more to print?
- JNZ OUTBYT
- CMP SI,Offset CODEND ; End of area?
- JNZ BYTLOP
- MOV DX,Offset ENDTXT ; Yes, add trailer: 34H and CR LF
- MOV AH,9
- INT 21H
- MOV AH,4CH ; End GENCOM program section
- INT 21H
-
- ENDTXT DB 34H ; End of file marker for loader
- CRLF DB 13,10,"$"
-
- CODE ENDS
- END START
-